package org.cgc.gui;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.filechooser.FileFilter;

import org.cgc.log.GraphLogic;
import org.cgc.obj.Graph;
import org.cgc.obj.GraphColoringInfo;

public class GCWindow extends JFrame implements MouseListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	//GUI
	private JPanel pane, fPane;
	private GCPanel gPane;

	JFileChooser fileChooser, exportChooser;
	
	//Images
	private static ImageIcon addVIcon = new ImageIcon("Img/AddVert.png");
	private static ImageIcon delVIcon = new ImageIcon("Img/DelVert.png");
	private static ImageIcon addEIcon = new ImageIcon("Img/AddEdge.png");
	private static ImageIcon delEIcon = new ImageIcon("Img/DelEdge.png");
	private static ImageIcon colGIcon = new ImageIcon("Img/ColorGraph.png");
	
	//Menu
	private JMenuBar menuBar;
	
	//Logic
	private Graph graph;
	private GraphColoringInfo gci;
	
	private List<Integer> selected;
	
	public GCWindow() {
		super("Contrast graph coloring");
		
		graph = new Graph(0, 0);
		gci = new GraphColoringInfo();
		selected = new ArrayList<Integer>();
		
		GraphLogic.initForbiddenDistances("0");

		initMenu();
		initView();
		
		fileChooser = new JFileChooser();
		fileChooser.addChoosableFileFilter(new FileFilter() {
			
			@Override
			public String getDescription() {
				return "Graph format";
			}
			
			@Override
			public boolean accept(File arg0) {
				if(arg0.getName().contains(".txt")) return true;
				if(!arg0.getName().contains(".")) return true;
				return false;
			}
		});
		
		exportChooser = new JFileChooser();
		exportChooser.addChoosableFileFilter(new FileFilter() {
			
			@Override
			public String getDescription() {
				return "Contrast colored graph format (.ccg)";
			}
			
			@Override
			public boolean accept(File arg0) {
				if(arg0.getName().contains(".ccg")) return true;
				return false;
			}
		});
		
		gPane.addMouseListener(this);
		
		setSize(800, 600);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}
	
	private void initMenu() {
		//------------------------------------------------
		//File
		JMenuItem create = new JMenuItem("Create");
		JMenuItem open = new JMenuItem("Open");
		JMenuItem save = new JMenuItem("Save");
		JMenuItem generate = new JMenuItem("Generate");
		JMenuItem export = new JMenuItem("Export");
		
		create.setToolTipText("Create new empty graph");
		open.setToolTipText("Open graph");
		save.setToolTipText("Save graph");
		generate.setToolTipText("Generate new random graph");
		export.setToolTipText("Export graph with coloring parameters");
		
		create.addActionListener(new CreateListener());
		open.addActionListener(new OpenListener());
		save.addActionListener(new SaveListener());
		generate.addActionListener(new GenerateListener());
		export.addActionListener(new ExportListener());
		
		JMenu action = new JMenu("File");
		action.add(create);
		action.add(open);
		action.add(save);
		action.add(new JSeparator());
		action.add(generate);
		//TODO switch on
		//action.add(export);
		
		//------------------------------------------------
		//Properties
		JMenuItem forbidden = new JMenuItem("Forbidden distances");
		JMenuItem maxIters = new JMenuItem("Max iterations");
		
		forbidden.setToolTipText("Specify set of forbidden distances");
		maxIters.setToolTipText("Set maximum number of iterations");
		
		forbidden.addActionListener(new ForbiddenDistancesListener());
		maxIters.addActionListener(new MaxIterationsListener());
		
		JMenu properties = new JMenu("Properties");
		properties.add(forbidden);
		properties.add(maxIters);
		
		//------------------------------------------------
		//Help
		JMenuItem info = new JMenuItem("Info");
		JMenuItem authors = new JMenuItem("Authors");
		
		info.setToolTipText("Show information about this program");
		authors.setToolTipText("Show information about authors");
		
		info.addActionListener(new InfoListener());
		authors.addActionListener(new AuthorsListener());
		
		JMenu help = new JMenu("Help");
		help.add(info);
		help.add(authors);
		
		menuBar = new JMenuBar();
		menuBar.add(action);
		menuBar.add(properties);
		menuBar.add(help);
		setJMenuBar(menuBar);
	}
	
	private void initView() {
		gPane = new GCPanel(graph, gci, selected);
		
		fPane = new JPanel(new GridLayout(1, 9));
		
		JButton bAddVertex = new JButton();
		JButton bDeleteVertex = new JButton();
		JButton bAddEdge = new JButton();
		JButton bDeleteEdge = new JButton();
		JButton bColor = new JButton();
		
		bAddVertex.setIcon(addVIcon);
		bDeleteVertex.setIcon(delVIcon);
		bAddEdge.setIcon(addEIcon);
		bDeleteEdge.setIcon(delEIcon);
		bColor.setIcon(colGIcon);
		
		bAddVertex.setToolTipText("Add vertex");
		bDeleteVertex.setToolTipText("Delete selected vertices");
		bAddEdge.setToolTipText("Add edges between selected vertices");
		bDeleteEdge.setToolTipText("Delete edges between selected vertices");
		bColor.setToolTipText("Color graph");
		
		bAddVertex.addActionListener(new AddVertexListener());
		bDeleteVertex.addActionListener(new DeleteVertexListener());
		bAddEdge.addActionListener(new AddEdgeListener());
		bDeleteEdge.addActionListener(new DeleteEdgeListener());
		bColor.addActionListener(new ColorGraphListener());
		
		fPane.add(new JLabel());
		fPane.add(bAddVertex);
		fPane.add(bDeleteVertex);
		fPane.add(bAddEdge);
		fPane.add(bDeleteEdge);
		fPane.add(new JLabel());
		fPane.add(bColor);
		fPane.add(new JLabel());
		
		pane = new JPanel(new BorderLayout());
		pane.add(fPane, BorderLayout.NORTH);
		pane.add(gPane, BorderLayout.CENTER);
		
		add(pane);
	}
	
	public Graph getGraph() {
		return graph;
	}
	
	//------------------------------------------------------------------------------
	//ActionListeners
	
	private class AddVertexListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			graph.addVertex();
			repaint();
		}
	}
	
	private class DeleteVertexListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			graph.delVertices(selected);
			selected.clear();
			repaint();
		}
	}
	
	private class AddEdgeListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			graph.setEdges(selected, true);
			repaint();
		}
	}
	
	private class DeleteEdgeListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			graph.setEdges(selected, false);
			repaint();
		}
	}
	
	private class ColorGraphListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent e) {
			if(graph.getVertNumber() > 1 &&
					graph.getMaxDeg() > 0) {
				GraphLogic.colorGraph(graph, gci);
				repaint();
			}
		}
	}
	
	private class CreateListener implements ActionListener {	
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			new CreateWindow(GCWindow.this);
		}
	}
	
	private class OpenListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			int returnVal = fileChooser.showOpenDialog(GCWindow.this);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				File file = fileChooser.getSelectedFile();
				if(file != null) {
					GraphLogic.initGraph(graph, file);
					repaint();
				}
			}
		}
	}
	
	private class SaveListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			int returnVal = fileChooser.showSaveDialog(GCWindow.this);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				File file = fileChooser.getSelectedFile();
				if(file != null) {
					GraphLogic.saveGraph(graph, file);
				}
			}
		}
	}
	
	private class GenerateListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			new GenerateWindow(GCWindow.this);
		}
	}
	
	private class ExportListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			int returnVal = exportChooser.showSaveDialog(GCWindow.this);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				File file = exportChooser.getSelectedFile();
				if(file != null) {
					GraphLogic.saveColoredGraph(graph, file);
				}
			}
		}
	}
	
	private class ForbiddenDistancesListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			new ForbiddenDistancesWindow();
		}
	}
	
	private class MaxIterationsListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			new MaxIterationsWindow();
		}
	}

	private class InfoListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			new InfoWindow("Help/Info.html");
		}
	}
	
	private class AuthorsListener implements ActionListener {
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			new InfoWindow("Help/Authors.html");
		}
	}

	public static void main(String[] str) {
		new GCWindow();
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {}

	@Override
	public void mouseEntered(MouseEvent arg0) {}

	@Override
	public void mouseExited(MouseEvent arg0) {}

	@Override
	public void mousePressed(MouseEvent arg0) {
		switch(arg0.getButton()) {
		case MouseEvent.BUTTON1:
			int indx = gPane.getGv().
				getSelectedVertexIndex(arg0.getX(), arg0.getY());
			if(indx >= 0) {
				Iterator<Integer> it = selected.iterator();
				while(it.hasNext()) {
					if(it.next() == indx) return;
				}
				selected.add(indx);
			}
			break;
		case MouseEvent.BUTTON3:
			selected.clear();
			break;
		}
		repaint();
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {}
}
